package javango.api;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javango.core.contextprocessors.ContextProcessor;
import javango.middleware.Middleware;

import com.google.inject.Binder;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;

/**
 *  
 * @author johns
 *
 */

import java.util.Arrays;
import java.util.Collections;

/**
 * Base implementation of Settings, configure 
 * in constructor via {@link Settings#setUrlsClass(java.lang.Class)}, 
 * {@link Settings#addMiddlewareClasses(java.lang.Class<? extends javango.middleware.Middleware>[])} and
 * {@link Settings#addContextProcessors(java.lang.Class<? extends javango.core.contextprocessors.ContextProcessor>[])}.
 * 
 */
public class BaseSettings implements Settings,Module {
    
    private Class<? extends Urls> urlsClass;
    private List<Class<? extends Middleware>> middlewareClasses;
    private List<Class<? extends ContextProcessor>> contextProcessorClasses;
    private List<Class<? extends Module>> moduleClasses;

    private boolean debug;
    private Map<String, String> localMap = new HashMap<String, String>();

    public Class<? extends Urls> getUrlsClass() {
        return urlsClass;
    }

    final public void setUrlsClass(Class<? extends Urls> urlsClass) {
        if (this.urlsClass != null) {
            throw new IllegalStateException("urlsClass already initialized - cannot be called twice");
        }
        this.urlsClass = urlsClass;
    }
    
    final public void addMiddlewareClasses(Class<? extends Middleware> ...middlewareClassesArray) {
        if (this.middlewareClasses == null) {
        	middlewareClasses = new ArrayList<Class<? extends Middleware>>();
        } 
        middlewareClasses.addAll(Arrays.asList(middlewareClassesArray));
    }

    public List<Class<? extends Middleware>> getMiddlewareClasses() {
        if (middlewareClasses == null) {
            return new ArrayList<Class<? extends Middleware>>();
        } else {
            return Collections.unmodifiableList(middlewareClasses);
        }
    }

    final public List<Class<? extends ContextProcessor>> getContextProcessorClasses() {
        if (contextProcessorClasses == null) {
            return new ArrayList<Class<? extends ContextProcessor>>();
        } else {
            return Collections.unmodifiableList(contextProcessorClasses);
        }
    }

    final public void addContextProcessorClasses(Class<? extends ContextProcessor> ...contextProcessorsArray) {
        if (this.contextProcessorClasses == null) {
        	contextProcessorClasses = new ArrayList<Class<? extends ContextProcessor>>();
        }
        contextProcessorClasses.addAll(Arrays.asList(contextProcessorsArray));
    }

    final public List<Class<? extends Module>> getModuleClasses() {
        return moduleClasses;
    }

    final public void addModuleClasses(Class<? extends Module> ...moduleClassesArray) {
        if (this.moduleClasses != null) {
        	moduleClasses = new ArrayList<Class<? extends Module>>();
        }
        moduleClasses.addAll(Arrays.asList(moduleClassesArray));
    }

    
    final public boolean isDebug() {
        return debug;
    }

    final public void setDebug(boolean debug) {
        this.debug = debug;
    }

    final public boolean isValid() {
        // TODO: valid if eg. is Urls class was set
        return true;
    }
    
    final public String get(String property) {		
		if (localMap.containsKey(property)) return localMap.get(property);
		return null;
	}
	
    final public void set(String property, String value) {
		localMap.put(property, value);
	}

    final public String get(String property, String defaultValue) {
		String value = get(property);
		if (value == null) return defaultValue;
		return value;
	}

	Injector injector;
	
	public void configure(Binder arg0) {
		arg0.bind(Settings.class).toInstance(this);
	}

	public Injector createInjector(List<Module> moduleList) {
		if (moduleList == null) {
			moduleList = new ArrayList<Module>();
		}
		
		moduleList.add(this);
		
		injector = Guice.createInjector(moduleList);
		return injector;
	}

	
}
